using System;
using System.ComponentModel;
using System.Data;
using System.Timers;
using Oracle.ManagedDataAccess.Types;
using OracleInternal.BulkCopy;
using OracleInternal.Common;
using OracleInternal.MTS;
using OracleInternal.ServiceObjects;

namespace Oracle.ManagedDataAccess.Client
{
	public sealed class OracleBulkCopy : IDisposable
	{
		private int m_batchSize;

		private OracleBulkCopyOptions m_bulkCopyOptions;

		private int m_timeout;

		private OracleBulkCopyColumnMappingCollection m_columnMappings;

		private OracleConnection m_connection;

		private string m_destinationTableName;

		private string m_destinationPartitionName;

		private string m_destinationSchemaName;

		private int m_notifyAfter;

		private int m_badRowNumber;

		private int m_badColNumber;

		private bool m_ownConnection;

		private bool m_insideRowsCopiedEvent;

		private bool m_fetchMeta;

		private DataTable m_destinationtableMetaData;

		private OracleRowsCopiedEventHandler m_rowsCopiedEventHandler;

		private bool m_disposed;

		private bool m_timeElapsed;

		private const int DEFAULT_TIMEOUT = 30;

		private const int ONE_SECOND = 1000;

		private OracleBulkCopyImpl m_bulkCopyImpl;

		[DefaultValue(0)]
		public int BatchSize
		{
			get
			{
				return m_batchSize;
			}
			set
			{
				if (value < 0)
				{
					throw new ArgumentOutOfRangeException("BatchSize");
				}
				m_batchSize = value;
			}
		}

		[DefaultValue(OracleBulkCopyOptions.Default)]
		public OracleBulkCopyOptions BulkCopyOptions
		{
			get
			{
				return m_bulkCopyOptions;
			}
			set
			{
				m_bulkCopyOptions = value;
			}
		}

		[DefaultValue(30)]
		public int BulkCopyTimeout
		{
			get
			{
				return m_timeout;
			}
			set
			{
				if (value < 0)
				{
					throw new ArgumentOutOfRangeException("BulkCopyTimeout");
				}
				m_timeout = value;
			}
		}

		public OracleBulkCopyColumnMappingCollection ColumnMappings
		{
			get
			{
				if (m_columnMappings == null)
				{
					m_columnMappings = new OracleBulkCopyColumnMappingCollection();
				}
				return m_columnMappings;
			}
		}

		public OracleConnection Connection => m_connection;

		public string DestinationTableName
		{
			get
			{
				if (m_destinationTableName == null)
				{
					return string.Empty;
				}
				return m_destinationTableName;
			}
			set
			{
				if (value == null)
				{
					throw new ArgumentNullException("DestinationTableName");
				}
				if (value.Length == 0)
				{
					throw new ArgumentException("DestinationTableName");
				}
				if (m_destinationTableName != value)
				{
					m_fetchMeta = true;
					m_destinationTableName = value;
				}
			}
		}

		public string DestinationPartitionName
		{
			get
			{
				if (m_destinationPartitionName == null)
				{
					return string.Empty;
				}
				return m_destinationPartitionName;
			}
			set
			{
				m_destinationPartitionName = value;
			}
		}

		public string DestinationSchemaName
		{
			get
			{
				if (m_destinationSchemaName == null)
				{
					return string.Empty;
				}
				return m_destinationSchemaName;
			}
			set
			{
				m_destinationSchemaName = value;
			}
		}

		[DefaultValue(0)]
		public int NotifyAfter
		{
			get
			{
				return m_notifyAfter;
			}
			set
			{
				if (value < 0)
				{
					throw new ArgumentOutOfRangeException("NotifyAfter");
				}
				m_notifyAfter = value;
			}
		}

		internal bool TimeElapsed => m_timeElapsed;

		public event OracleRowsCopiedEventHandler OracleRowsCopied
		{
			add
			{
				m_rowsCopiedEventHandler = (OracleRowsCopiedEventHandler)Delegate.Combine(m_rowsCopiedEventHandler, value);
			}
			remove
			{
				m_rowsCopiedEventHandler = (OracleRowsCopiedEventHandler)Delegate.Remove(m_rowsCopiedEventHandler, value);
			}
		}

		~OracleBulkCopy()
		{
			Dispose(disposing: false);
		}

		public OracleBulkCopy(OracleConnection connection)
		{
			if (connection == null)
			{
				throw new ArgumentNullException("connection");
			}
			if (connection.State != ConnectionState.Open)
			{
				throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.CON_CLOSED));
			}
			m_connection = connection;
			m_timeout = 30;
			m_bulkCopyOptions = OracleBulkCopyOptions.Default;
			m_bulkCopyImpl = new OracleBulkCopyImpl(this);
		}

		public OracleBulkCopy(string connectionString)
		{
			if (connectionString == null)
			{
				throw new ArgumentNullException("connectionString");
			}
			if (connectionString == string.Empty)
			{
				throw new ArgumentException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.ODP_INVALID_VALUE, "connectionString"));
			}
			m_connection = new OracleConnection(connectionString);
			m_ownConnection = true;
			m_timeout = 30;
			m_bulkCopyOptions = OracleBulkCopyOptions.Default;
		}

		public OracleBulkCopy(OracleConnection connection, OracleBulkCopyOptions copyOptions)
			: this(connection)
		{
			m_bulkCopyOptions = copyOptions;
		}

		public OracleBulkCopy(string connectionString, OracleBulkCopyOptions copyOptions)
			: this(connectionString)
		{
			m_bulkCopyOptions = copyOptions;
		}

		public void Close()
		{
			if (m_insideRowsCopiedEvent)
			{
				throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.BC_INV_OPER_INSIDE_EVENT));
			}
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		public void WriteToServer(DataRow[] rows)
		{
			if (m_disposed)
			{
				throw new ObjectDisposedException(GetType().Name);
			}
			if (rows == null)
			{
				throw new ArgumentNullException("rows");
			}
			if (m_destinationTableName == null)
			{
				throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.ODP_INVALID_VALUE, "Destination table"));
			}
			BulkCopySourceDataRows bulkCopySourceDataRows = null;
			bulkCopySourceDataRows = new BulkCopySourceDataRows(rows[0].Table, this, BatchSize);
			WriteDataSourceToServer(bulkCopySourceDataRows);
		}

		public void WriteToServer(DataTable table)
		{
			WriteToServer(table, (DataRowState)0);
		}

		public void WriteToServer(IDataReader reader)
		{
			if (m_disposed)
			{
				throw new ObjectDisposedException(GetType().Name);
			}
			if (reader == null)
			{
				throw new ArgumentNullException("reader");
			}
			if (m_destinationTableName == null)
			{
				throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.ODP_INVALID_VALUE, "Destination table"));
			}
			if (reader is OracleDataReader)
			{
				BulkCopySourceOracleDataReader bulkCopySourceOracleDataReader = null;
				bulkCopySourceOracleDataReader = new BulkCopySourceOracleDataReader((OracleDataReader)reader, this, BatchSize);
				WriteDataSourceToServer(bulkCopySourceOracleDataReader);
			}
			else
			{
				BulkCopySourceDataReader bulkCopySourceDataReader = null;
				bulkCopySourceDataReader = new BulkCopySourceDataReader(reader, this, BatchSize);
				WriteDataSourceToServer(bulkCopySourceDataReader);
			}
		}

		public void WriteToServer(DataTable table, DataRowState rowState)
		{
			if (m_disposed)
			{
				throw new ObjectDisposedException(GetType().Name);
			}
			if (table == null)
			{
				throw new ArgumentNullException("table");
			}
			if (m_destinationTableName == null)
			{
				throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.ODP_INVALID_VALUE, "Destination table"));
			}
			BulkCopySourceDataTable bulkCopySourceDataTable = null;
			rowState &= ~DataRowState.Deleted;
			bulkCopySourceDataTable = new BulkCopySourceDataTable(table, this, BatchSize, rowState);
			WriteDataSourceToServer(bulkCopySourceDataTable);
		}

		public void WriteToServer(OracleRefCursor refCursor)
		{
			if (m_disposed)
			{
				throw new ObjectDisposedException(GetType().Name);
			}
			if (refCursor == null)
			{
				throw new ArgumentNullException("refCursor");
			}
			if (m_destinationTableName == null)
			{
				throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.ODP_INVALID_VALUE, "Destination table"));
			}
			WriteToServer(refCursor.GetDataReader());
		}

		private void Dispose(bool disposing)
		{
			if (m_disposed)
			{
				return;
			}
			if (disposing)
			{
				m_columnMappings = null;
				if (m_connection != null)
				{
					if (m_ownConnection)
					{
						m_connection.Dispose();
					}
					m_connection = null;
				}
			}
			m_disposed = true;
		}

		private bool IsBulkCopyOption(OracleBulkCopyOptions copyOption)
		{
			return (m_bulkCopyOptions & copyOption) == copyOption;
		}

		private DataTable GetDestinationTableMetaData()
		{
			if (m_fetchMeta)
			{
				OracleCommand oracleCommand = new OracleCommand();
				string commandText;
				if (m_destinationSchemaName != null && !m_destinationSchemaName.Equals(string.Empty))
				{
					commandText = "DECLARE  table_name VARCHAR2(128 char);  schema_name VARCHAR2(128 char);  query VARCHAR2(300 char);  BEGIN  schema_name := SYS.DBMS_ASSERT.SIMPLE_SQL_NAME(:p_schema_name);  table_name := SYS.DBMS_ASSERT.SIMPLE_SQL_NAME(:p_table_name);  query := 'select * from ' || schema_name || '.' || table_name || ' where 1=2';  OPEN :p_cursor for query;  END;";
					oracleCommand.Parameters.Add("p_schema_name", m_destinationSchemaName);
					oracleCommand.Parameters.Add("p_table_name", m_destinationTableName);
					oracleCommand.Parameters.Add("p_cursor", OracleDbType.RefCursor).Direction = ParameterDirection.Output;
				}
				else
				{
					commandText = "DECLARE  table_name VARCHAR2(128 char);  query VARCHAR2(300 char);  BEGIN  table_name:= SYS.DBMS_ASSERT.SIMPLE_SQL_NAME(:p_table_name);  query:= 'select * from ' || table_name || ' where 1=2';  OPEN :p_cursor for query;  END;";
					oracleCommand.Parameters.Add("p_table_name", m_destinationTableName);
					oracleCommand.Parameters.Add("p_cursor", OracleDbType.RefCursor).Direction = ParameterDirection.Output;
				}
				oracleCommand.CommandText = commandText;
				oracleCommand.Connection = m_connection;
				oracleCommand.ExecuteNonQuery();
				OracleDataReader dataReader = ((OracleRefCursor)oracleCommand.Parameters["p_cursor"].Value).GetDataReader();
				m_destinationtableMetaData = dataReader.GetSchemaTable();
				m_fetchMeta = false;
			}
			return m_destinationtableMetaData;
		}

		private OracleBulkCopyColumnMappingCollection CreateInternalColumnMappings(IBulkCopyDataSource dataSource)
		{
			bool flag = false;
			OracleBulkCopyColumnMappingCollection oracleBulkCopyColumnMappingCollection = new OracleBulkCopyColumnMappingCollection();
			if (m_columnMappings == null || m_columnMappings.Count == 0)
			{
				oracleBulkCopyColumnMappingCollection.CreateDefaultColumnMapping(dataSource.GetColumnCount());
				flag = true;
			}
			else
			{
				foreach (OracleBulkCopyColumnMapping columnMapping in m_columnMappings)
				{
					oracleBulkCopyColumnMappingCollection.Add(columnMapping.Clone());
				}
				oracleBulkCopyColumnMappingCollection.ValidateCollection();
			}
			DataTable dataTable = null;
			int num = -1;
			foreach (OracleBulkCopyColumnMapping item in oracleBulkCopyColumnMappingCollection)
			{
				if (item.SourceOrdinal == -1)
				{
					num = dataSource.GetColumnOrdinal(item.SourceColumn);
					if (num == -1)
					{
						throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.ODP_INVALID_VALUE, "Column mapping"));
					}
					item.SourceOrdinal = num;
				}
				if (string.IsNullOrEmpty(item.DestinationColumn))
				{
					if (dataTable == null)
					{
						dataTable = GetDestinationTableMetaData();
					}
					if (item.DestinationOrdinal >= dataTable.Rows.Count)
					{
						throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.ODP_INVALID_VALUE, "Column mapping"));
					}
					item.DestinationColumn = (string)dataTable.Rows[item.DestinationOrdinal][0];
				}
			}
			if (!flag)
			{
				oracleBulkCopyColumnMappingCollection.Sort();
			}
			return oracleBulkCopyColumnMappingCollection;
		}

		private void WriteDataSourceToServer(IBulkCopyDataSource dataSource)
		{
			Timer timer = null;
			OracleBulkCopyColumnMappingCollection oracleBulkCopyColumnMappingCollection = null;
			try
			{
				ValidateConnection();
				bool flag = m_connection.m_oracleConnectionImpl.m_mtsTxnCtx != null && m_connection.m_oracleConnectionImpl.m_mtsTxnCtx.m_txnType != MTSTxnType.None;
				if (IsBulkCopyOption(OracleBulkCopyOptions.UseInternalTransaction) && (m_connection.m_oraTransaction != null || flag))
				{
					throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.CON_ALREADY_TXNED));
				}
				if (m_columnMappings != null)
				{
					m_columnMappings.BulkCopyInProgress = true;
				}
				oracleBulkCopyColumnMappingCollection = CreateInternalColumnMappings(dataSource);
				m_timeElapsed = false;
				if (m_timeout != 0)
				{
					timer = new Timer();
					timer.Elapsed += OnTimeElapsed;
					if (m_timeout >= 2147483)
					{
						timer.Interval = 2147483647.0;
					}
					else
					{
						timer.Interval = m_timeout * 1000;
					}
					timer.AutoReset = false;
					timer.Enabled = true;
				}
				string schemaName = ((m_destinationSchemaName == null || m_destinationSchemaName.Equals(string.Empty)) ? m_connection.m_cs.m_userId : m_destinationSchemaName);
				m_bulkCopyImpl.Init(dataSource, oracleBulkCopyColumnMappingCollection, schemaName, DestinationTableName, DestinationPartitionName);
				ColumnDescribeInfo[] array = null;
				BulkCopyResult bulkCopyResult = (BulkCopyResult)0;
				bool flag2 = false;
				int batchSize = dataSource.GetBatchSize();
				if (batchSize <= 0)
				{
					return;
				}
				while ((bulkCopyResult & BulkCopyResult.UserAbort) == 0 && (bulkCopyResult & BulkCopyResult.Timeout) == 0 && (bulkCopyResult & BulkCopyResult.AllRowRead) == 0)
				{
					if (!flag2)
					{
						array = m_bulkCopyImpl.Prepare();
						dataSource.Initialize(array);
						flag2 = true;
					}
					else if (m_bulkCopyOptions == OracleBulkCopyOptions.UseInternalTransaction)
					{
						array = m_bulkCopyImpl.Prepare();
					}
					bulkCopyResult = m_bulkCopyImpl.ProcessBatch(batchSize);
					if ((bulkCopyResult & BulkCopyResult.Success) != 0 && m_bulkCopyOptions == OracleBulkCopyOptions.UseInternalTransaction)
					{
						m_bulkCopyImpl.Commit();
					}
					if ((bulkCopyResult & BulkCopyResult.Timeout) != 0)
					{
						m_bulkCopyImpl.Abort();
						throw new OracleException(ResourceStringConstants.BC_OPER_TIMEOUT, string.Empty, string.Empty, OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.BC_OPER_TIMEOUT));
					}
					if ((bulkCopyResult & BulkCopyResult.UserAbort) != 0)
					{
						m_bulkCopyImpl.Abort();
						throw new OracleException(ResourceStringConstants.BC_OPER_ABORT, string.Empty, string.Empty, OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.BC_OPER_ABORT));
					}
				}
				if ((bulkCopyResult & BulkCopyResult.AllRowRead) != 0 && m_bulkCopyOptions != OracleBulkCopyOptions.UseInternalTransaction)
				{
					m_bulkCopyImpl.Commit();
				}
			}
			finally
			{
				if (timer != null)
				{
					timer.Enabled = false;
					timer.Dispose();
				}
				if (m_columnMappings != null)
				{
					m_columnMappings.BulkCopyInProgress = false;
				}
				m_timeElapsed = false;
			}
		}

		private void ValidateConnection()
		{
			if (m_ownConnection && m_connection.State != ConnectionState.Open)
			{
				m_connection.Open();
				m_bulkCopyImpl = new OracleBulkCopyImpl(this);
			}
			else if (m_connection.State != ConnectionState.Open)
			{
				throw new InvalidOperationException(OracleStringResourceManager.GetErrorMesg(ResourceStringConstants.CON_CLOSED));
			}
		}

		internal bool FireRowsCopiedEvent(long rowsCopied)
		{
			OracleRowsCopiedEventArgs oracleRowsCopiedEventArgs;
			try
			{
				oracleRowsCopiedEventArgs = new OracleRowsCopiedEventArgs(rowsCopied);
				m_insideRowsCopiedEvent = true;
				OnRowsCopied(oracleRowsCopiedEventArgs);
			}
			finally
			{
				m_insideRowsCopiedEvent = false;
			}
			return oracleRowsCopiedEventArgs.Abort;
		}

		internal void OnRowsCopied(OracleRowsCopiedEventArgs eventArgs)
		{
			if (m_rowsCopiedEventHandler != null)
			{
				m_rowsCopiedEventHandler(this, eventArgs);
			}
		}

		private void OnTimeElapsed(object source, ElapsedEventArgs e)
		{
			m_timeElapsed = true;
		}
	}
}
